﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace Morro.VPN.Desktop.DataDisplay
{
    public class Scattergram : BaseGraph
    {
        ///// <summary>
        ///// Начало координат в системе координат графика
        ///// </summary>
        //private Point _nullPoint;

        //Половина ширины эллипса
        private int _ellipseWidthHalf;

        private List<int> _points;
        private List<Point> _pointsList;

        //Минимальное значение по ОХ
        private double _legendMinX;

        //Максимальное значение по ОУ
        private double _legendMaxX;


        //Диагональная линия
        private Pen _diagonalPen;

        //Эллипсы - точки
        private Ellipse[] _ellipses;

        //Точки на осях
        private Brush _asisPointBrush;



        public Scattergram()
        {

            _ellipseWidthHalf = 2;
            //_nullPoint = new Point(10, 10);

            _legendMinX = 500;
            _legendMaxX = 1500;

            Brush diagonalbrush = new SolidColorBrush(Colors.MediumTurquoise);
            diagonalbrush.Opacity = 0.5;
            _diagonalPen = new Pen(diagonalbrush, 1);

            _asisPointBrush = new SolidColorBrush(Colors.Wheat);

            SizeChanged += new SizeChangedEventHandler(Scattergram_SizeChanged);
        }


        private double _width;
        private double _height;
        //private bool sizeLock = true;
        void Scattergram_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            _width = this.ActualWidth;
            _height = this.ActualHeight;

            //make bigger if not
            if (_width == _height)
                return;

            double max = _height > _width ? _height : _width;
            //this.Width = max;
            //this.Height = max;
            //this.setWidthHeightVars();
        }

        public void ApplyLegend(double x, double y)
        {
            _legendMinX = x;
            _legendMaxX = y;
            UpdateUICore();
        }

        public void AutoScale()
        {
            int min = _points.Min() / 10;
            int max = _points.Max() / 10;

            _legendMinX = min * 10 - 50;
            _legendMaxX = max * 10 + 50;

            UpdateUICore();
        }


        private double _minX;
        private double _minY;
        private double _maxX;
        private double _maxY;


        public void ShowData(List<int> points)
        {
            _points = points;
            _pointsList = new List<Point>();

            for (int i = 0; i < points.Count; i++)
            {
                if (i > points.Count - 2)
                    break;

                _pointsList.Add(new Point(points[i], points[i + 1]));
            }

            _minX = _pointsList.Min(x => x.X);
            _minY = _pointsList.Min(x => x.Y);
            _maxY = _pointsList.Max(x => x.Y);
            _maxX = _pointsList.Max(x => x.X);

            //_minPoint = points.Min();
            //_maxPoint = points.Max();

            if (_ellipses != null && _ellipses.Length > 0)
            {
                //empty array
            }

            _ellipses = new Ellipse[_pointsList.Count];
            Brush pointBrush = new SolidColorBrush(Colors.Yellow);
            int ellipseSize = _ellipseWidthHalf*2;
            for (int i = 0; i < _pointsList.Count; i++)
            {

                Ellipse ellipse = new Ellipse();
                Point p = TranslateScattegram(_pointsList[i].X, _pointsList[i].Y);
                ellipse.SetValue(Canvas.LeftProperty, p.X - _ellipseWidthHalf);
                ellipse.SetValue(Canvas.TopProperty, p.Y -_ellipseWidthHalf);
                ellipse.Width = ellipseSize;
                ellipse.Height = ellipseSize;
                ellipse.Fill = pointBrush;
                ellipse.ToolTip = string.Format("{0}: [{1:0},{2:0}]", i, _pointsList[i].X, _pointsList[i].Y);
                _ellipses[i] = ellipse;

                this.Children.Add(ellipse);
            }

            SetCaption("Скаттерограмма");



            UpdateUICore();
        }



        public override void DrawAsix(DrawingContext dc)
        {
            //base.DrawAsix(dc);

            Point oX1 = TranslateToCanvas(0, 0);
            Point oX2 = TranslateToCanvas(0, DrawAreaHeight);

            Point oY1 = TranslateToCanvas(0, 0);
            Point oy2 = TranslateToCanvas(DrawAreaWidth, 0);

            dc.DrawLine(AsisPen, oX1, oX2);
            dc.DrawLine(AsisPen, oY1, oy2);


            Point oXY1 = TranslateToCanvas(0, 0);
            double max = Math.Max(DrawAreaWidth, DrawAreaHeight);
            Point oXY2 = TranslateToCanvas(max, max);
            dc.DrawLine(_diagonalPen, oXY1, oXY2);


            double left = DrawAreaLeft;
            double width = DrawAreaWidth;
            double stepWidth = 1;

            if (_snapAsisXPoints.Length >= 2)
            {
                stepWidth = _snapAsisXPoints[1] - _snapAsisXPoints[0];
            }

            //Сколько в одной единице ширины
            double k = (_legendMaxX - _legendMinX) / DrawAreaWidth;

            //Не правильно считаются шаги
            //Считаются до крайней правой точки, соотсветственно не учитывается что правее
            //int step = (int)((_legendMaxX - _legendMinX) / _snapAsisXPoints.Length);//((int)Math.Round((_legendMaxX - _legendMinX) / _snapAsisXPoints.Length / 10.0)) * 10;
            int step = (int)(stepWidth * k);

            for (int i = 0; i < _snapAsisXPoints.Length; i++)
            {
                double valueValue = _legendMinX + i * step;
                //string value = string.Format("{0:0}", _legendMinX + i * step);
                string value = string.Format("{0:0}", valueValue);
                FormattedText text = new FormattedText(value,
                                                       CultureInfo.GetCultureInfo("ru-RU"),
                                                       FlowDirection.LeftToRight,
                                                       new Typeface("Verdana"),
                                                       12, Brushes.White);

                Point p = TranslateToCanvas(_snapAsisXPoints[i], text.Height + 1);
                dc.DrawText(text, p);

                dc.DrawEllipse(_asisPointBrush, null, TranslateToCanvas(_snapAsisXPoints[i], 0), 3, 3);
            }

            stepWidth = 1;
            if(_snapAsisYPoints.Length >=2)
            {
                stepWidth = _snapAsisYPoints[1] - _snapAsisYPoints[0];
            }

            k = (_legendMaxX - _legendMinX)/DrawAreaHeight;
            step = (int) (stepWidth*k);


            //int stepY = (int)((_legendMaxX - _legendMinX) / _snapAsisYPoints.Length);//((int)Math.Round((_legendMaxX - _legendMinX) / _snapAsisXPoints.Length / 10.0)) * 10;
            for (int i = 0; i < _snapAsisYPoints.Length; i++)
            {
                string value = string.Format("{0:0}", _legendMinX + i * step);
                FormattedText text = new FormattedText(value,
                                                       CultureInfo.GetCultureInfo("ru-RU"),
                                                       FlowDirection.LeftToRight,
                                                       new Typeface("Verdana"),
                                                       12, Brushes.White);

                Point p = TranslateToCanvas(3, _snapAsisYPoints[i]);
                dc.DrawText(text, p);

                dc.DrawEllipse(_asisPointBrush, null, TranslateToCanvas(0, _snapAsisYPoints[i]), 3, 3);
            }
        }

        /// <summary>
        /// Позиционирует точку относительно ширины рабочей плоскости относительно осей
        /// С учетом минимального значения по ОСИ и максимального значения по ОСИ
        /// Если минимальное 0 максимальное 100, а х = 30, то он так и получится в 30
        /// А затем позиционируется для рисования
        /// </summary>
        protected Point TranslateScattegram(double x, double y)
        {
            int min = (int)_legendMinX;
            int max = (int)_legendMaxX;

            //высчитываем коэффициенты 
            double pRRX = (x - min) / (max - min);
            double pRRY = (y - min) / (max - min);


            //Новые значения
            double xValue = pRRX * DrawAreaWidth;
            double yValue = pRRY * DrawAreaHeight;

            return TranslateToCanvas(xValue, yValue);
        }

        public void SetEllipseSize(int newSize)
        {
            _ellipseWidthHalf = newSize;
            UpdateUICore();
        }

        protected override void OnRender(DrawingContext dc)
        {
            base.OnRender(dc);

            if (_points == null || _points.Count == 0)
                return;

            Brush pointBrush = new SolidColorBrush(Colors.Yellow);
            int ellipseSize = _ellipseWidthHalf*2;
            for (int i = 0; i < _pointsList.Count; i++)
            {

                Point p = TranslateScattegram(_pointsList[i].X, _pointsList[i].Y);//, _minPoint, _maxPoint);
                //dc.DrawEllipse(pointBrush, null, p, 2, 2);
                Canvas.SetLeft(_ellipses[i], p.X - _ellipseWidthHalf);
                Canvas.SetTop(_ellipses[i], p.Y - _ellipseWidthHalf);
                _ellipses[i].Width = ellipseSize;
                _ellipses[i].Height = ellipseSize;
            }


            //max rectanlge
            Brush rectBrush = new SolidColorBrush(Colors.YellowGreen);
            Pen border = new Pen(rectBrush, 1);
            border.DashStyle = DashStyles.Dash;

            Point p1 = TranslateScattegram(_minX, _minY);
            Point p2 = TranslateScattegram(_maxX, _maxY);
            dc.DrawRectangle(null, border, new Rect(p1, p2));

        }


    }
}
